// bitstream.c: example utility functions for streaming bits to a data decompressor.
// Written 5/30/14 by David Krauss. No rights reserved.

#include <stdint.h>
#include <stdbool.h>
#include <limits.h>

#if TRACE_HPACK_HUFFMAN
#include <stdio.h>
#endif

#include "bitstream.h"

extern uint8_t hpack_huffman_get_byte( struct hpack_huffman_bit_source * source ) {
	uint8_t next = source->pen < source->end? * source->pen : UCHAR_MAX;
	++ source->pen;
	uint8_t result = source->bit_buf | ( next >> source->bit_buf_size );
	source->bit_buf = next << ( 8 - source->bit_buf_size );
	
#if TRACE_HPACK_HUFFMAN
	printf( "get_byte %x @ %p residual %x:%d\n", next, source->pen, source->bit_buf, source->bit_buf_size );
#endif
	
	return result;
}

extern uint8_t hpack_huffman_get_bits( struct hpack_huffman_bit_source * source, uint8_t head, uint8_t n ) {
#if TRACE_HPACK_HUFFMAN
	printf( "get_bits %d\n", n );
#endif
	
	uint8_t result = head << n;
	uint8_t done = 8 - n;
	
	result |= source->bit_buf >> done;
	
	if ( n <= source->bit_buf_size ) {
		source->bit_buf <<= n;
		source->bit_buf_size -= n;
		
		return result;
	}
	
	done += source->bit_buf_size;
	source->bit_buf_size = done;
	
	uint8_t next = source->pen < source->end? * source->pen ++ : UCHAR_MAX;
#if TRACE_HPACK_HUFFMAN
	printf( "+ byte %x @ %p\n", next, source->pen );
#endif
	
	result |= next >> done;
	
	source->bit_buf = next << ( 8 - done );
	
	return result;
}

extern void hpack_huffman_unget_bits( struct hpack_huffman_bit_source * source, uint8_t tail, uint8_t n ) {
#if TRACE_HPACK_HUFFMAN
	printf( "unget_bits %d <= %x\n", n, tail );
#endif
	
	if ( n + source->bit_buf_size < 8 ) {
		source->bit_buf = source->bit_buf >> n | tail << ( 8 - n );
		source->bit_buf_size += n;
	
	} else {
#if TRACE_HPACK_HUFFMAN
		printf( "- byte\n" );
#endif
		
		source->bit_buf_size = n + source->bit_buf_size - 8;
		source->bit_buf = tail << ( 8 - n ) & ~ ( ( 0x80 >> ( source->bit_buf_size - 1 ) ) - 1 );
		-- source->pen;
	}
#if TRACE_HPACK_HUFFMAN
	printf( "residual %x:%d\n", source->bit_buf, source->bit_buf_size );
#endif
}

extern bool hpack_huffman_at_end( struct hpack_huffman_bit_source * source ) {
	return source->pen >= source->end;
}
